/** \file    TransformingIterator.h
  * \brief   Classes in the file iterate through two rasters simultaniously.
  *  OrdinaryRaster is iterated in pixel-by-pixel order, that is ordibary.
  *  TransformingRaster is iterated through floating point pixels (in general case),
  *  corresponding to ordinary position in first raster by some transform.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/PatchMaker/src/TransformingIterator.h,v 1.8 2007/07/22 06:38:44 cscom1r4 Exp $
  */

#ifndef _TransformingIterator_h_
#define _TransformingIterator_h_

#include <glib/g2/triangle.h>
#include <imglib/color.h>
typedef img::BGRA<unsigned char> ByteColor;
typedef img::BGRA<float> FloatColor;

//TI - color "interpretation" in TransformingRaster
template <class OR, class TR, class TI>
class TransformingIteratorBase {
public:
	typedef typename OR::iterator raster_iterator;
	typedef typename raster_iterator::value_type value_type;
public:
	TransformingIteratorBase(OR & oraster, TR & traster, TI const & ti) : 
		_oraster(oraster), _traster(traster), _ti(ti) {}
	bool operator != (const raster_iterator & rhs) const
		{ return _x != rhs.x() || _y != rhs.y(); }
	value_type operator * () 
		{ return _oraster(_x, _y); }
	unsigned x() const
		{ return _x; }
	unsigned y() const
		{ return _y; }
	operator size_point() const
		{ return size_point(_x, _y); }
	TI const & Interpretation()
		{ return _ti; }
protected:
	OR & _oraster;
	TR & _traster;
	TI _ti;
	unsigned _x, _y;
};

////////////////////////////////
// AffineTransformingIterator //
////////////////////////////////

template <class OR, class TR, class TI>
class AffineTransformingIterator : public TransformingIteratorBase<OR, TR, TI> {
public:
	AffineTransformingIterator(OR & oraster, TR & traster, TI const & ti, const Affine & a) : 
		TransformingIteratorBase<OR, TR, TI>(oraster, traster, ti), _a(a.inverse())/*, _shift(0.0, 0.0)*/ 
	{
		_inc = int_point(_a.xx, _a.yx);
		_fast_int_arithm = (fabs(_a.xx) < 10 && fabs(_a.yx) < 10);
	}
	AffineTransformingIterator & operator = (const raster_iterator & rhs) {
		_x = rhs.x();
		_y = rhs.y();
		UpdateAlt();
		return * this;
	}
	AffineTransformingIterator & operator ++() { 
		++_x;
		if (_x == _oraster.width()) 
			{ ++_y; _x = 0; UpdateAlt(); } 
		else
			IncAlt();
		return * this; 
	}
	const float_point & Alt() const
		{ return _alt/* + _shift*/; }
	const int_point & iAlt() const
		{ return _ialt; }
/*protected:
	const float_point & shift() const
		{ return _shift; }
	void shift(const float_point & sh)
		{ _shift = sh; }*/
private:
	void UpdateAlt() {
		_alt = _a(_x, _y); 
		_ialt = int_point(floor(_alt.x), floor(_alt.y));
	} 
	//updates image of affine transform caused by incrementation of preimage by (1,0)
	void IncAlt() {
		_alt.x += float(_a.xx);
		_alt.y += float(_a.yx);
		if (_fast_int_arithm) {
			_ialt += _inc;
			while (_alt.x < _ialt.x)
				--_ialt.x;
			while (_alt.x >= _ialt.x + 1)
				++_ialt.x;
			while (_alt.y < _ialt.y)
				--_ialt.y;
			while (_alt.y >= _ialt.y + 1)
				++_ialt.y;
		}
		else
			_ialt = int_point(floor(_alt.x), floor(_alt.y));
	}
private:
	const Affine _a;
	float_point _alt;
	int_point _ialt;
	int_point _inc; ///< int(_a.xx, _a.yx)
	bool _fast_int_arithm;
	//float_point _shift;
};

////////////////////////////
// AffineBilinearIterator //
////////////////////////////

template <class OR, class TR, class TI>
class AffineBilinearIteratorT : public AffineTransformingIterator<OR, TR, TI> {
public:
	typedef AffineTransformingIterator<OR, TR, TI> superclass;
public:
	AffineBilinearIteratorT(OR & oraster, TR const & traster, TI const & ti, const Affine & a) : 
		superclass(oraster, traster, ti, a)
	{
		//(0.5;0.5) required by fast bilinear interpolation
		//shift(float_point(0.5, 0.5));
	}
	AffineBilinearIteratorT & operator = (const raster_iterator & rhs) {
		*static_cast<superclass*>(this) = rhs;
		return * this;
	}

	template <class T>
	bool Interpolate(T & res) const {
		typename TI::result_type tmp;
		bool b = img::bilinear_preint(_ti, tmp, _traster, Alt(), iAlt());
		res = tmp;
		return b;
	}
	template <>
	bool Interpolate(typename TI::result_type & res) const {
		return img::bilinear_preint(_ti, res, _traster, Alt(), iAlt());
	}
};

template <class OR, class TR, class TI> 
inline AffineBilinearIteratorT<OR, TR, TI> 
AffineBilinearIterator(OR & oraster, TR & traster, TI const & ti, const Affine & a)
{
	return AffineBilinearIteratorT<OR, TR, TI>(oraster, traster, ti, a);
}

/////////////////////////////////////
// AffineMonotoneQuadraticIterator //
/////////////////////////////////////

struct FloatColorDerivativeZeroTest {
	bool operator() (FloatColor const & d0, FloatColor const & d1) const
		{ return d0.b * d1.b < 0 || d0.g * d1.g < 0 || d0.r * d1.r < 0 || d0.a * d1.a < 0; }
};

// MonotoneQuadratic inherits Bilinear because MQ may swap to it on the border of an image
template <class OR, class TR, class TI>
class AffineMonotoneQuadraticIteratorT : public AffineBilinearIteratorT<OR, TR, TI> {
public:
	typedef AffineBilinearIteratorT<OR, TR, TI> superclass;
public:
	AffineMonotoneQuadraticIteratorT(OR & oraster, TR const & traster, TI const & ti, const Affine & a) : 
		superclass(oraster, traster, ti, a)
		{ }
	AffineMonotoneQuadraticIteratorT & operator = (const raster_iterator & rhs) {
		*static_cast<superclass*>(this) = rhs;
		return * this;
	}

	/// it is used for interpolation of 0 & 1 in binary mask, no real need in monotone-quadratic reconstruction
	bool Interpolate(float & res) const 
		{ return superclass::Interpolate(res); }
	bool Interpolate(FloatColor & res) const {
		int_point i = iAlt();
		if (i.x < 0 || i.y < 0)
			return false;
		size_point f(i.x / 2 * 2, i.y / 2 * 2);
		if (f.x + 2 >= _traster.width() || f.y + 2 >= _traster.height()) {
			if (i.x + 1 >= _traster.width() || i.y + 1 >= _traster.height())
				return false;
			return superclass::Interpolate(res);
		}
		float_point a = Alt() - float_point(f);
		if (a.x + a.y < 2) {
			res = g2::trianglef(g2::vectorf(0,0), g2::vectorf(0,2), g2::vectorf(2,0)).
				monotone_quadratic(
					a,
					FloatColor(_traster[f]), //u0
					FloatColor(_traster[f + size_point(0,2)]), //u1
					FloatColor(_traster[f + size_point(2,0)]), //u2
					FloatColor(_traster[f + size_point(0,1)]), //u01
					FloatColor(_traster[f + size_point(1,1)]), //u12 
					FloatColor(_traster[f + size_point(1,0)]), //u20
					FloatColorDerivativeZeroTest());
		}
		else {
			res = g2::trianglef(g2::vectorf(0,2), g2::vectorf(2,2), g2::vectorf(2,0)).
				monotone_quadratic(
					a,
					FloatColor(_traster[f + size_point(0,2)]), //u0
					FloatColor(_traster[f + size_point(2,2)]), //u1
					FloatColor(_traster[f + size_point(2,0)]), //u2
					FloatColor(_traster[f + size_point(1,2)]), //u01
					FloatColor(_traster[f + size_point(2,1)]), //u12 
					FloatColor(_traster[f + size_point(1,1)]), //u20
					FloatColorDerivativeZeroTest());
		}
		return true;
	}
	bool Interpolate(ByteColor & res) const {
		FloatColor tmp;
		if (!Interpolate(tmp))
			return false;
		res = tmp;
		return true;
	}
};

template <class OR, class TR, class TI> 
inline AffineMonotoneQuadraticIteratorT<OR, TR, TI> 
AffineMonotoneQuadraticIterator(OR & oraster, TR & traster, TI const & ti, const Affine & a)
{
	return AffineMonotoneQuadraticIteratorT<OR, TR, TI>(oraster, traster, ti, a);
}
/*
////////////////////////////////////////////////////////
// AffineMonotoneQuadraticIndependentChannelsIterator //
////////////////////////////////////////////////////////

// MonotoneQuadraticIndependentChannels inherits Bilinear because MQ may swap to it on the border of an image
template <class OR, class TR, class TI>
class AffineMonotoneQuadraticIndependentChannelsIteratorT : public AffineBilinearIteratorT<OR, TR, TI> {
public:
	typedef AffineBilinearIteratorT<OR, TR, TI> superclass;
public:
	AffineMonotoneQuadraticIndependentChannelsIteratorT(OR & oraster, TR const & traster, TI const & ti, const Affine & a) : 
		superclass(oraster, traster, ti, a)
		{ }
	AffineMonotoneQuadraticIndependentChannelsIteratorT & operator = (const raster_iterator & rhs) {
		*static_cast<superclass*>(this) = rhs;
		return * this;
	}

	/// it is used for interpolation of 0 & 1 in binary mask, no real need in monotone-quadratic reconstruction
	bool Interpolate(float & res) const 
		{ return superclass::Interpolate(res); }
	bool Interpolate(FloatColor & res) const {
		int_point i = iAlt();
		if (i.x < 0 || i.y < 0)
			return false;
		size_point f(i.x / 2 * 2, i.y / 2 * 2);
		if (f.x + 2 >= _traster.width() || f.y + 2 >= _traster.height()) {
			if (i.x + 1 >= _traster.width() || i.y + 1 >= _traster.height())
				return false;
			return superclass::Interpolate(res);
		}
		float_point a = Alt() - float_point(f);
		if (a.x + a.y < 2) {
			IndependentlyInterpolate(res,
				g2::trianglef(g2::vectorf(0,0), g2::vectorf(0,2), g2::vectorf(2,0)), a,
				_traster[f], //u0
				_traster[f + size_point(0,2)], //u1
				_traster[f + size_point(2,0)], //u2
				_traster[f + size_point(0,1)], //u01
				_traster[f + size_point(1,1)], //u12 
				_traster[f + size_point(1,0)]);  //u20
		}
		else {
			IndependentlyInterpolate(res,
				g2::trianglef(g2::vectorf(0,2), g2::vectorf(2,2), g2::vectorf(2,0)), a,
				_traster[f + size_point(0,2)], //u0
				_traster[f + size_point(2,2)], //u1
				_traster[f + size_point(2,0)], //u2
				_traster[f + size_point(1,2)], //u01
				_traster[f + size_point(2,1)], //u12 
				_traster[f + size_point(1,1)]); //u20
		}
		return true;
	}
	bool Interpolate(ByteColor & res) const {
		FloatColor tmp;
		if (!Interpolate(tmp))
			return false;
		res = tmp;
		return true;
	}
private:
	typedef typename TR::elem_type TR_elem_type;
	void IndependentlyInterpolate(FloatColor & res,
		g2::trianglef const & t, float_point const & p,
		TR_elem_type const & u0, TR_elem_type const & u1, TR_elem_type const & u2, 
		TR_elem_type const & u01, TR_elem_type const & u12, TR_elem_type const & u20) const
	{
		res.b = t.monotone_quadratic(p,	u0.b, u1.b, u2.b, u01.b, u12.b, u20.b);
		res.g = t.monotone_quadratic(p,	u0.g, u1.g, u2.g, u01.g, u12.g, u20.g);
		res.r = t.monotone_quadratic(p,	u0.r, u1.r, u2.r, u01.r, u12.r, u20.r);
		res.a = t.monotone_quadratic(p,	u0.a, u1.a, u2.a, u01.a, u12.a, u20.a);
	}
};

template <class OR, class TR, class TI> 
inline AffineMonotoneQuadraticIndependentChannelsIteratorT<OR, TR, TI> 
AffineMonotoneQuadraticIndependentChannelsIterator(OR & oraster, TR & traster, TI const & ti, const Affine & a)
{
	return AffineMonotoneQuadraticIndependentChannelsIteratorT<OR, TR, TI>(oraster, traster, ti, a);
}
*/
////////////////////////////////////
// AffineNearestNeighbourIterator //
////////////////////////////////////

template <class OR, class TR, class TI>
class AffineNearestNeighbourIteratorT : public AffineTransformingIterator<OR, TR, TI> {
public:
	typedef AffineTransformingIterator<OR, TR, TI> superclass;
public:
	AffineNearestNeighbourIteratorT(OR & oraster, TR & traster, TI const & ti, const Affine & a) : 
		superclass(oraster, traster, ti, a) {}
	AffineNearestNeighbourIteratorT & operator = (const raster_iterator & rhs) {
		*static_cast<superclass*>(this) = rhs;
		return * this;
	}

	template <class T>
	bool Interpolate(T & res) const {
		int nx = (Alt().x < iAlt().x + 0.5f) ? iAlt().x : iAlt().x + 1;
		if (nx < 0 || nx >= int(_traster.width()))
			return false;
		int ny = (Alt().y < iAlt().y + 0.5f) ? iAlt().y : iAlt().y + 1;
		if (ny < 0 || ny >= int(_traster.height()))
			return false;
		_ti(_traster[size_point(nx, ny)], res);
		return true;
	}
};

template <class OR, class TR, class TI> 
inline AffineNearestNeighbourIteratorT<OR, TR, TI> 
AffineNearestNeighbourIterator(OR & oraster, TR & traster, TI const & ti, const Affine & a)
{
	return AffineNearestNeighbourIteratorT<OR, TR, TI>(oraster, traster, ti, a);
}

//////////////////////////////
// ExactTranslationIterator //
//////////////////////////////

template <class OR, class TR, class TI>
class ExactTranslationIteratorT : public TransformingIteratorBase<OR, TR, TI> {
public:
	typedef TransformingIteratorBase<OR, TR, TI> superclass;
public:
	ExactTranslationIteratorT(OR & oraster, TR & traster, TI const & ti, int dx, int dy) : 
		superclass(oraster, traster, ti), _dx(-dx), _dy(-dy) {}
	ExactTranslationIteratorT & operator = (const raster_iterator & rhs) {
		_x = rhs.x();
		_y = rhs.y();
		return * this;
	}
	ExactTranslationIteratorT & operator ++() { 
		++_x;
		if (_x == _oraster.width()) 
			{ ++_y; _x = 0; } 
		return * this; 
	}
	template <class T>
	bool Interpolate(T & res) const {
		int nx = _x + _dx;
		if (nx < 0 || nx >= int(_traster.width()))
			return false;
		int ny = _y + _dy;
		if (ny < 0 || ny >= int(_traster.height()))
			return false;
		_ti(_traster[size_point(nx, ny)], res);
		return true;
	}

private:
	int _dx, _dy;
};

template <class OR, class TR, class TI> 
inline ExactTranslationIteratorT<OR, TR, TI> 
ExactTranslationIterator(OR & oraster, TR & traster, TI const & ti, int dx, int dy)
{
	return ExactTranslationIteratorT<OR, TR, TI>(oraster, traster, ti, dx, dy);
}

//////////////////////////////////////////////////////////////////////////
// GiveAppropriateIterator - automatically choose between Bilinear & NN //
//////////////////////////////////////////////////////////////////////////

template <class F, class OR, class TR, class TI>
inline void GiveAppropriateIterator(InterpolationStyle istyle, const F & f,
	OR & oraster, TR & traster, TI const & ti, const Affine & a)
{
	int_point d;
	if (a.int_translation(&d))
		return f(ExactTranslationIterator(oraster, traster, ti, d.x, d.y));
	switch (istyle) {
	default:
		assert (false);
	case NearestNeighbour:
		return f(AffineNearestNeighbourIterator(oraster, traster, ti, a));
	case Bilinear:
		return f(AffineBilinearIterator(oraster, traster, ti, a));
	case MonotoneQuadratic:
		return f(AffineMonotoneQuadraticIterator(oraster, traster, ti, a));
	//case MonotoneQuadraticIndependentChannels:
	//	return f(AffineMonotoneQuadraticIndependentChannelsIterator(oraster, traster, ti, a));
	}
}

#endif //_TransformingIterator_h_
